Skip to content

feat: add pre-commit hooks and PR title validation#13

Merged
aryeko merged 2 commits intomainfrom
chore/s4-precommit-hooks
Feb 5, 2026
Merged

feat: add pre-commit hooks and PR title validation#13
aryeko merged 2 commits intomainfrom
chore/s4-precommit-hooks

Conversation

@aryeko
Copy link
Collaborator

@aryeko aryeko commented Feb 5, 2026

Summary

Implements S4: Pre-commit Hooks from the SDLC plan.

Changes

  1. Local pre-commit hooks via lefthook.yml:

    • gofmt - checks code formatting
    • goimports - checks import formatting
    • golangci-lint - runs linter on staged files
    • All run in parallel for speed
  2. CI PR title validation:

    • New pr-title job validates PR titles follow conventional commits
    • Uses amannn/action-semantic-pull-request@v5
    • Ensures squash-merge commit messages are properly formatted
  3. MASTER.md updated:

    • Marked S4 as complete (🟢)

Architecture

Local:     pre-commit → fmt/lint checks → commit-msg → commitlint
CI:        PR opened → pr-title job validates conventional format
Merge:     Squash uses PR title (validated by CI)

Note on Branch Rulesets

GitHub's commit_message_pattern ruleset feature is not available in the free tier. The implementation relies on:

  • Local pre-commit hooks (can be bypassed with --no-verify)
  • CI PR title validation (cannot be bypassed)

For enterprise repos, branch rulesets can be added via GitHub UI for additional enforcement.

Test Plan

  • Ran make fmt && make lint && make test - all pass
  • Committed changes - pre-commit hooks executed successfully
  • Commit message validated by commitlint hook

To test locally:

# Update hooks
make setup-hooks

# Try committing unformatted code
echo "package main;func main(){}" > test.go
git add test.go
git commit -m "test: formatting check"  # Should fail pre-commit

Made with Cursor

Summary by CodeRabbit

  • Chores
    • Added CI check to validate pull request titles automatically.
    • Configured pre-commit hooks to enforce formatting, import ordering, and linting for Go and to validate commit messages.
    • Updated internal project plan statuses to mark two previously deferred items as complete.

- Add lefthook pre-commit hooks for gofmt, goimports, golangci-lint
- Add CI job to validate PR titles follow conventional commits
- Update MASTER.md to mark S4 (Pre-commit Hooks) as complete

Note: Branch rulesets with commit_message_pattern not available in
free tier, so enforcement relies on local hooks + PR title checks.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Updates development workflows: adds Lefthook pre-commit and commit-msg checks, introduces a CI job to validate semantic PR titles, and marks two SDLC entries (S4 Pre-commit Hooks, S5 Test Coverage) as complete in the master plan.

Changes

Cohort / File(s) Summary
Plan update
.github/internal/plans/MASTER.md
Changed status for S4 (Pre-commit Hooks) and S5 (Test Coverage) from Deferred to Complete.
CI workflow
.github/workflows/ci.yml
Added a new "Validate PR Title" job that runs on pull_request using amannn/action-semantic-pull-request@v5 with GITHUB_TOKEN.
Pre-commit & commit-msg hooks
lefthook.yml
Added Lefthook configuration: parallel pre-commit hooks running gofmt, goimports, golangci-lint on staged Go files and a commit-msg hook invoking commitlint via GOBIN/GOPATH bin.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I nibble code and tidy strings,
Hooks and CI give tidy things,
Titles checked before they land,
Tests and lint held in my hand,
Hooray — the rabbit hops, well-planned! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add pre-commit hooks and PR title validation' directly and accurately describes the main changes: adding pre-commit hooks (lefthook.yml) and PR title validation (CI workflow). It is clear, specific, and follows conventional commit format.
Description check ✅ Passed The PR description includes most required sections: Summary explaining what and why, detailed Changes with bullet points, Architecture diagram, Test Plan with verification steps, and notes on design decisions. All key template sections are covered.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/s4-precommit-hooks

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link

codecov-commenter commented Feb 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lefthook.yml`:
- Around line 4-20: The gofmt/goimports hooks hang and hide real failures when
no Go files are staged because the current run uses command substitution and
allows formatters to read stdin; update the gofmt and goimports command entries
(the "gofmt" and "goimports" commands) to first check whether {staged_files} is
empty and skip early if so, otherwise run the formatter directly on the file
list and return the formatter's exit status (do not wrap the formatter in test
-z "$(…)" which masks its exit code); ensure the implementation preserves and
propagates the formatter exit code so failures are visible in the pre-commit
hook.

- Guard when no Go files staged
- Preserve formatter exit codes

Co-authored-by: Cursor <cursoragent@cursor.com>
@aryeko aryeko merged commit 62e4733 into main Feb 5, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet